/* application class using GLWindow
** base code from nehe.gamedev.net
**
** the following 5 methods must be provided by derived class:
** GL_Application * GL_Application::create(const char * class_name)			
**		create your derived class and return a GL_Application pointer
** bool initialize();
**		perform all your initialization
** void deinitialize();
**		perform all your deinitialization
** void update(DWORD milliseconds);
**		perform your motion updates
**		'milliseconds' is the number of milliseconds passed since the last call
**		with whatever accuracy GetTickCount() provides
** void draw();
**		perform all your scene drawing				
*/


#ifndef _GLAPP_H
#define _GLAPP_H

#include "common\GLWindow.h"

enum APP_MSG
{
  MSG_NONE,
  MSG_QUIT,
  MSG_TOGGLE_FULLSCREEN
};

class Keys
{
public:
	Keys() {clear();}
	void clear() {ZeroMemory(&m_keyDown,sizeof(m_keyDown));}
	bool isPressed(unsigned int key) {return ( (key<MAX_KEYS) ? (m_keyDown[key]==true) : false );}
	void setPressed(unsigned int key) {if(key<MAX_KEYS) m_keyDown[key]=true;}
	void setReleased(unsigned int key) {if(key<MAX_KEYS) m_keyDown[key]=false;}
private:
	static const unsigned int MAX_KEYS=256;
	bool m_keyDown[MAX_KEYS];
};

class Mouse
{
public:
  Mouse() {clear();}
  void clear() {m_LMBDown=m_RMBDown=m_LMBClick=m_RMBClick=false;}
  bool isPressed(int button) {return (button == 0)?m_LMBDown:m_RMBDown;}
	void setPressed(int button) {if(button == 0) m_LMBDown = true; else m_RMBDown = true;}
	void setReleased(int button) {if(button == 0) m_LMBDown = false; else m_RMBDown = false;}
  void setClick(int button, unsigned int x, unsigned int y) {m_clickX=x;m_clickY=y;if(button == 0) m_LMBClick = true; else m_RMBClick = true;}
  void doneClick(int button) {if(button == 0) m_LMBClick = false; else m_RMBClick = false;}
  bool isClick(int button) {return (button == 0)?m_LMBClick:m_RMBClick;}
  void setXY(unsigned int x, unsigned int y) {m_x=x;m_y=y;}
  unsigned int getX() {return m_x;}
  unsigned int getY() {return m_y;}
  unsigned int getClickX() {return m_x;}
  unsigned int getClickY() {return m_y;}
private:
  unsigned int m_x;
  unsigned int m_y;
  unsigned int m_clickX;
  unsigned int m_clickY;
  bool m_LMBDown;
  bool m_RMBDown;
  bool m_LMBClick;
  bool m_RMBClick;
};

class GL_Application
{
public:
	static GL_Application* create(const char* className);
	virtual ~GL_Application() {}
protected:
	virtual bool initialize()=0;
	virtual void deinitialize()=0;
	virtual void update(DWORD milliseconds)=0;
	virtual void draw()=0;
	void toggleFullScreen();
	void terminateApplication();
	void resizeDraw(bool enable) {m_resizeDraw=enable;}
	Keys m_keys;
  Mouse m_mouse;
	GL_Application(const char* className);
  GL_Window m_window;
private:
	friend int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow);
	int Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow);
	friend LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	LRESULT Message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	static const UINT WM_TOGGLEFULLSCREEN=(WM_USER+1);	
	const char* m_className;
	bool m_isProgramLooping;
	bool m_createFullScreen;
	bool m_isVisible;
	bool m_resizeDraw;
	DWORD m_lastTickCount;
};

#endif